package ru.jetsoft.reg112.desktop.data;

import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import ru.jetsoft.reg112.desktop.BaseException;
import ru.jetsoft.reg112.desktop.InitException;

public class ParamCache {

    private static final String tagEntity = "entity";
    private static final String tagRecord = "record";

    private static final String attrId = "id";
    private static final String attrName = "name";
    private static final String attrType = "type";
    private static final String attrRequired = "required";
    private static final String attrMultiple = "multiple";
    private static final String attrPattern = "pattern";
    private static final String attrDefault = "default";
    private static final String attrTooltip = "tooltip";
//    private static final String attrOrder = "order";

    private final static List<Param> rootParams = new LinkedList<>();
    private final static Map<Integer, Param> params = new HashMap<>();

    public static void load(String filename) throws InitException {
        try {
            validateForm(filename);
            DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
            Document doc = dBuilder.parse(filename);

            NodeList entities = doc.getElementsByTagName(tagEntity);
            if(entities.getLength() != 1) {
                throw new BaseException("Not found expected single entity. Found " + entities.getLength() + ".");
            }
            Node entity = entities.item(0);
            NodeList records = entity.getChildNodes();
            loadParams(records, true);
        } catch(Exception ex) {
            throw new InitException("Failed to load form parameters from " + filename, ex);
        }
    }

    private static List<Param> loadParams(NodeList records, boolean root) throws InitException {
        Node record;
        NamedNodeMap attributes;
        Param param;
        Node attr;
        List<Param> paramList = new LinkedList<>();
        for(int i = 0; i < records.getLength(); i++) {
            record = records.item(i);
            if(tagRecord.equals(record.getNodeName())) {
                attributes = record.getAttributes();
                param = new Param();
                for(int j = 0; j < attributes.getLength(); j++) {
                    attr = attributes.item(j);
                    switch(attr.getNodeName()) {
                        case attrId:
                            param.setId(Integer.valueOf(attr.getNodeValue()));
                            break;
                        case attrName:
                            param.setName(attr.getNodeValue());
                            break;
                        case attrType:
                            param.setType(Integer.valueOf(attr.getNodeValue()));
                            break;
                        case attrRequired:
                            param.setRequired(Boolean.valueOf(attr.getNodeValue()));
                            break;
                        case attrMultiple:
                            param.setMultiple(Boolean.valueOf(attr.getNodeValue()));
                            break;
                        case attrPattern:
                            param.setPattern(attr.getNodeValue());
                            break;
                        case attrDefault:
                            param.setDefaultValue(attr.getNodeValue());
                            break;
                        case attrTooltip:
                            param.setTooltip(attr.getNodeValue());
                            break;
//                        case attrOrder:
//                            param.setOrder(Integer.valueOf(attr.getNodeValue()));
//                            break;
                        default:
                            throw new InitException("Unknows attribute " + attr.getNodeName());
                    }
                }
                List<Param> childs = loadParams(record.getChildNodes(), false);
                param.setChilds(childs);
                paramList.add(param);
                params.put(param.getId(), param);
                if(root) {
                    rootParams.add(param);
                }
            }
        }
        return paramList;
    }

    private static void validateForm(String filename) throws BaseException {
        //todo: validate xml using xsd
    }

    public static Collection<Param> getParams() {
        return params.values();
    }

    public static Collection<Param> getRootParams() {
        return rootParams;
    }

    public static Param getParam(int id) {
        return params.get(id);
    }
}
